#ifndef _RANDOMPOINT_H_
#define _RANDOMPOINT_H_

class Random_generator
{
public:
	void set_range(double inf, double sup){}
	double generate_double()  {return this->r1.get_double();}
	double generate_double(double low, double up) {return this->r1.get_double(low, up);}
private:
	CGAL::Random r1 ; 
};

class Triangle
{
public:
	double area()
	{
		if (fabs(m_area ) < ERROR )
		{
			return f_area();
		}
		else
		{
			return m_area; 
		}
	}
	void random_point(Mesh::Point & random_point)
	{
		double random_number = random_obj.generate_double();
		//Manage how to implement the random_point in one triangle. 
	}

	Triangle & operator = (const Triangle & obj)
	{
		this->point[0] = obj.point[0];
		this->point[1] = obj.point[1];
		this->point[2] = obj.point[2];
		this->m_area = obj.m_area;
		this->m_face_handle = obj.m_face_handle; 
		return *this;
	}
	Triangle(const Triangle & obj)
	{
		this->point[0] = obj.point[0];
		this->point[1] = obj.point[1];
		this->point[2] = obj.point[2];
		this->m_area = obj.m_area;
		this->m_face_handle = obj.m_face_handle; 
	}
	Triangle (const Mesh::Point point[3], Mesh::FaceHandle face_handle)
	{
		random_obj.set_range(0.0f,1.0f);
		this->point[0] = point[0];
		this->point[1] = point[1];
		this->point[2] = point[2];
		m_area = this->f_area();
		this->m_face_handle = face_handle;
	}
	Triangle()
	{
		Mesh::Point p(0,0,0);
		point[0] = p; point[1] = p; point[2] = p;
		m_area = 0;
	}
	void generate_random_point (Mesh::Point & random_point, Mesh::FaceHandle & fh)
	{
		double s = this->random_generator.generate_double();
		double t = this->random_generator.generate_double();
		if (s + t > 1.0f)
		{
			s = 1.0f - s; t = 1.0f - t;
		}
		double a = 1.0f - s - t;
		double b = s; 
		double c = t;
		
		for (int i = 0;i < 3; ++i)
		{
			random_point[i] = a * this->point[0][i] + b * this->point[1][i] + c * this->point[2][i]; 
		}
		fh = this->m_face_handle;
	}
private:
	double m_area ;
private:
	Mesh::Point point[3];
	double f_area()
	{
		double a = (point[0]-point[1]).length();
		double b = (point[1]-point[2]).length();
		double c = (point[2]-point[0]).length();
		double p = (a + b + c) / 2.0f;
		return sqrt(p * (p - a) * (p - b) * (p - c));
	}
private:
	Random_generator random_obj;
	Mesh::FaceHandle m_face_handle; 
	Random_generator random_generator; //generator double between [0, 1]
};

class Random_points_mesh
{
public:
	Random_points_mesh(Mesh & mesh)
	{
		set_range(mesh);
	}
protected:
	void set_range(Mesh & mesh)
	{
		for (Mesh::FaceIter f_it = mesh.faces_begin(); f_it!= mesh.faces_end(); ++f_it)
		{
			unsigned int count = 0;
			Mesh::Point point[3];
			for (Mesh::FaceVertexIter fv_it = mesh.fv_iter(f_it); fv_it; ++fv_it)
			{
				point[count++] = mesh.point(fv_it.handle());
			}
			Triangle tri(point, f_it.handle());
			this->mesh_faces.push_back(tri);
		}
		double length = 0.0;
		for (std::vector<Triangle>::iterator t_it = mesh_faces.begin(); t_it != mesh_faces.end(); ++t_it)
		{
			length += t_it->area();
			//std::cout<<length<<' ';
			range.push_back(length);
		}
		//std::cout<<std::endl;

		this->low_range = 0.0f;
		this->upper_range = length;

	}
public:
	void generate_point(Mesh::Point & point , Mesh::FaceHandle & fh)
	{ 
		static Random_generator random_gen;
		double s = random_gen.generate_double(low_range, upper_range);
		std::vector<double>::iterator range_v_it = upper_bound(range.begin(), range.end(),  s);
		int offset = range_v_it - range.begin() ;
		mesh_faces[offset].generate_random_point(point, fh);
	}
protected:
	//void triangle_random_point(const Triangle & tri, Mesh::Point & random_point){}
private:
	std::vector<Triangle> mesh_faces;
	std::vector<double> range; 
	double low_range ;
	double upper_range ;


};
#endif
